#pragma once
#include "Thread.hpp"
#include "Log.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include <functional>
#include <queue>

namespace ThreadPoolMoudule
{
    using namespace ThreadModule;
    using namespace LogModule;

    const int gdefaultthreadnum = 10;
    using thread_t = Thread;
    using p_thread_t = std::shared_ptr<thread_t>;
    template <typename T>
    class ThreadPool
    {
    private:
        // 消费者
        void HandlerTask(std::string name)
        {
            {
                LockGuard lockguard(_mutex);
                if (_is_running == false)
                {
                    LOG(LogLevel::INFO) << "服务器线程还未完整构建，阻塞等待...";
                    _start_cond.Wait();
                }
            }
            T t;
            while (true)
            {
                {
                    LockGuard lockguard(_mutex);
                    while (_tasks.empty() && _is_running)
                    {
                        // LOG(LogLevel::DEBUG) << name << "进入 HandlerTask 开始等待任务:_is_running = " << _is_running;
                        _wait_num++;
                        _cond.Wait();
                        _wait_num--;
                    }

                    // 1.若没有任务，停止HadlerTask
                    // 退出条件：任务队列为空 且 线程池已停止
                    if (_tasks.empty() && !_is_running)
                    {
                        LOG(LogLevel::DEBUG) << name << "任务为空且已停止，退出";
                        break;
                    }
                    // 2.若还有任务，取出任务直到任务取完
                    t = _tasks.front();
                    _tasks.pop();
                }

                // LOG(LogLevel::DEBUG) << name << "执行任务";
                t(); // 执行任务（出作用域，锁已释放）
            }
            LOG(LogLevel::DEBUG) << name << "线程正常退出";
        }
        void InitThreadPool()
        {
            for (int i = 0; i < _thread_num; ++i)
            {
                //                                      将this绑定到HandlerTask中,以适配线程构造所需的fuc_t = void()
                _threads.emplace_back(std::make_shared<thread_t>(std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1)));
                LOG(LogLevel::DEBUG) << "构建线程" << _threads.back()->Name() << "对象 ... 成功";
            }
        }
        ThreadPool(ThreadPool<T> &thread_pool) = delete;
        ThreadPool<T> &operator=(ThreadPool<T> &thread_pool) = delete;
        ThreadPool(int cap = gdefaultthreadnum)
            : _thread_num(cap), _cond(_mutex.Mutex_ptr()), _start_cond(_mutex.Mutex_ptr()), _wait_num(0), _is_running(false)
        {
            InitThreadPool();
        }

    public:
        static ThreadPool<T> *getInstance()
        {
            if (instance == NULL)
            {
                LockGuard lockguard(mutex);
                if (instance == NULL)
                {
                    LOG(LogLevel::INFO) << "单例首次被执行，需要加载对象...";
                    instance = new ThreadPool<T>();

                    // 启动单例
                    instance->Start();
                }
            }
            return instance;
        }
        void Start()
        {
            for (auto &thread : _threads)
            {
                LOG(LogLevel::DEBUG) << "thread:" << thread->Name() << " begin....";
                thread->Start();
            }
            _is_running = true;
            _start_cond.Broadcast();
        }

        // 必须wait不然主线程就会先与新线程退出
        void Wait()
        {
            for (auto &thread : _threads)
            {
                thread->Join();
                LOG(LogLevel::DEBUG) << thread->Name() << " 退出.... ";
            }
        }

        void Stop()
        {
            LockGuard lockguard(_mutex);
            if (_is_running)
            {
                _is_running = false;

                // 1.先唤醒所有线程 && 完成剩余任务后停止
                if (_wait_num > 0)
                    _cond.Broadcast();
            }
        }

        void Enqueue(const T &t)
        {

            LockGuard lockguard(_mutex);

            _tasks.emplace(t);

            if (_wait_num)
            {
                _cond.Signal();
                LOG(LogLevel::DEBUG) << "task push 唤醒一个线程";
            }
        }

    private:
        int _thread_num;
        std::vector<p_thread_t> _threads;
        std::queue<T> _tasks;
        Mutex _mutex;
        Cond _cond;
        Cond _start_cond;
        int _wait_num;
        bool _is_running;

        static ThreadPool<T> *instance;
        static Mutex mutex; // 只用来保护单例
    };

    // 模版声明
    template <typename T>
    ThreadPool<T> *ThreadPool<T>::instance;
    template <typename T>
    Mutex ThreadPool<T>::mutex;
}